﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Configuration;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using System.Diagnostics;
using CurrentCostUploader.CurrentCostService;
using CurrentCostLibrary;
using Microsoft.Practices.EnterpriseLibrary.Caching;

namespace CurrentCost
{
    public class Uploader
    {
        TimeSpan uploadInterval;
        bool firstRun = true;
        DateTime lastReadingDateTime = DateTime.Now;
        List<CurrentCostLiveReading> readings = new List<CurrentCostLiveReading>();
        CurrentCostDevice device = new CurrentCostDevice();
        Queue<CurrentCostLiveReading> readingsQueue = new Queue<CurrentCostLiveReading>();
        List<CurrentCostHourlyHistory> historyRecords = new List<CurrentCostHourlyHistory>();
        public Uploader()
        {
            try
            {
                Thread readingThread = new Thread(RunReadings);
                readingThread.Start();

                Thread updaterThread = new Thread(RunUpdater);
                updaterThread.Start();

                do
                {
                    Thread.Sleep(5000);
                } while (true);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public void RunUpdater()
        {
            
            do
            {
                ICacheManager cache = CacheFactory.GetCacheManager();
                var uploadReadings = new List<CurrentCostLiveReading>();
                {
                    CurrentCostLiveReading thisReading = null;
                    if (readingsQueue != null)
                    {
                        lock (readingsQueue)
                        {
                            try
                            {
                                
                                readingsQueue = (Queue<CurrentCostLiveReading>)cache.GetData("readingsQueue");
                                if (readingsQueue != null && readingsQueue.Count > 0)
                                {
                                    
                                    while (readingsQueue.Count >0)
	                                {	
                                        thisReading = readingsQueue.Dequeue();
                                        uploadReadings.Add(thisReading);

                                        cache.Add("readingsQueue", readingsQueue);
                                    }
                                }
                            }
                            catch (Exception deQueueExcep)
                            {
                                Console.WriteLine(deQueueExcep.Message);
                            }
                        }
                        if (uploadReadings.Count>0)
                        {
                            var client = new WeatherServiceClient();
                            try
                            {
                                client.Open();
                                Stopwatch stopwatch = new Stopwatch();
                                stopwatch.Start();


                                Console.WriteLine("Sending {1} readings to {0}", client.Endpoint.Address.Uri.ToString(), uploadReadings.Count);

                                //client.SaveCurrentCostReadingCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_SaveCurrentCostReadingCompleted);
                                //client.SaveCurrentCostReading(thisReading);
                                client.SaveCurrentCostReadings(uploadReadings);
                                client.Close();
                                stopwatch.Stop();
                                Console.WriteLine("Reading sent in {0} ", stopwatch.Elapsed.ToString());
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex.Message);
                                lock (readingsQueue)
                                {
                                    readingsQueue = (Queue<CurrentCostLiveReading>)cache.GetData("readingsQueue");
                                    foreach (var item in uploadReadings)
                                    {
                                        readingsQueue.Enqueue(item);
                                        cache.Add("readingsQueue", readingsQueue);
                                    }

                                }
                            }
                        }
                    }
                }

                
                Thread.Sleep((int)uploadInterval.TotalMilliseconds);
            } while (true);
        }

        public void RunReadings()
        {

            device.BaudRate = Convert.ToInt32(ConfigurationManager.AppSettings["baudRate"].ToString());
            device.Port = ConfigurationManager.AppSettings["port"].ToString();

            string uploadIntervalConfig = ConfigurationSettings.AppSettings["uploadInterval"];
            uploadInterval = SoapDuration.Parse(uploadIntervalConfig);

            Console.WriteLine("Listening on {0} at {1}.", device.Port, device.BaudRate);

            device.NewReading += new CurrentCostDevice.NewReadingHandler(device_NewReading);
            device.NewHourlyHistory += new CurrentCostDevice.NewHouryHistoryHandler(device_NewHourlyHistory);
            device.Open();
        }

        void device_NewHourlyHistory(object sender, HourlyHistoryEventArgs he)
        {
            historyRecords.Add(he.HourlyHistory);
        }

        void device_NewReading(object sender, ReadingEventArgs re)
        {

            //var client = new WeatherServiceClient();

            try
            {
                var newReading = re.LatestReading;
                Console.WriteLine("New reading at {0}, {1} watts", newReading.ReadingDateTime.ToString(), newReading.Watts);
                if (readingsQueue == null)
                {
                    readingsQueue = new Queue<CurrentCostLiveReading>();
                }
                lock (readingsQueue)
                {
                    readingsQueue.Enqueue(newReading);

                    ICacheManager cache = CacheFactory.GetCacheManager();
                    cache.Add("readingsQueue", readingsQueue);
                }


                /*
                client.Open();
                
                device.Close();
                Console.WriteLine("New reading at {0}, {1} watts", newReading.ReadingDateTime.ToString(), newReading.Watts);
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();

                
                Console.WriteLine("Sending to {0}",  client.Endpoint.Address.Uri.ToString());

                //client.SaveCurrentCostReadingCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_SaveCurrentCostReadingCompleted);
                client.SaveCurrentCostReading(newReading);
                client.Close();
                stopwatch.Stop();
                Console.WriteLine("Reading sent in {0} ", stopwatch.Elapsed.ToString());
                lastReadingDateTime = DateTime.Now;
                device.Open();

               */

                /*
                TimeSpan timeSpanSinceLastRun = DateTime.Now.Subtract(lastReadingDateTime);
                
                readings.Add(newReading);
                Console.WriteLine("New reading at {0}, {1} watts", newReading.ReadingDateTime.ToString(), newReading.Watts);

                 
                if (timeSpanSinceLastRun > uploadInterval)
                {

                    Stopwatch stopwatch = new Stopwatch();
                    stopwatch.Start();
                    device.Close();
                    client.Open();
                    Console.WriteLine("Sending {0} readings to {1}", readings.Count, client.Endpoint.Address.Uri.ToString());
                    var readingsToSend = readings;
                    readings = new List<CurrentCostReading>();
                    client.SaveCurrentCostReadingsCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_SaveCurrentCostReadingsCompleted);
                    client.SaveCurrentCostReadings(readingsToSend);
                    client.Close();
                    stopwatch.Stop();
                    
                    Console.WriteLine("Readings sent in {0} ", stopwatch.Elapsed.ToString());
                    lastReadingDateTime = DateTime.Now;
                    device.Open();
                }
                 */
            }
            catch (Exception ex)
            {
                //client.Abort();
                Console.WriteLine(ex.Message);
            }
        }

        void client_SaveCurrentCostReadingCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            Console.WriteLine("Completed send");
        }

        static void client_SaveCurrentCostReadingsCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            Console.WriteLine("Completed send");
        }
    }
}
